#pragma once

#include "noncopyable.h"
#include "Timestamp.h"

#include <functional>
#include <memory>

class EventLoop;

/**
 * 理清楚 EventLoop、Channel、Poller之间的关系。在Reactor模型上对应多路事件分发器
 * Channel 理解为通道 封装了sockfd和其感兴趣的事件event，比如EPOLLIN、EPOLLOUT
 * 还绑定了Poller返回的具体事件，Poller返回通知Channel发生的事件后，Channel调用相应的事件回调操作
 */

class Channel : noncopyable
{
public:
    using EventCallback = std::function<void()>;              // 事件回调
    using ReadEventCallback = std::function<void(Timestamp)>; // 只读事件回调
    Channel(EventLoop *loop, int fd);
    ~Channel();

    // 得到poller通知的发生的事件以后，处理事件的
    void handleEvent(Timestamp receiveTime);

    // 设置回调函数对象
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }
    void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }
    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }
    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }

    // 防止当channel被手动remove掉，channel还在执行回调操作
    void tie(const std::shared_ptr<void>&);

    int fd() const { return fd_; }                       // 获取当前channel的fd_
    int events() const { return events_; }               // 获取当前channel的感兴趣的事件events_
    void set_revents(int revt) { revents_ = revt; }      // used by poller

    // 设置fd相应的事件状态
    void enableReading() { events_ |= kReadEvent; update(); }
    void disableReading() { events_ &= ~kReadEvent; update(); }
    void enableWriting() { events_ |= kWriteEvent; update(); }
    void disableWriting() { events_ &= ~kWriteEvent; update(); }
    void disableAll() { events_ = kNoneEvent; update(); }
    
    // 返回channel fd当前的事件状态
    bool isNoneEvent() const { return events_ == kNoneEvent; }
    bool isWriting() const { return events_ & kWriteEvent; }
    bool isReading() const { return events_ & kReadEvent; }

    int index() { return index_; }              // 获取当前channel的状态index_
    void set_index(int idx) { index_ = idx; }   // 设置channel当前的状态 used by poller

    // 返回当前channel属于哪一个EventLoop
    // one loop per thread
    EventLoop* ownerLoop() { return loop_; }

    // 在Poller中移除Channel
    void remove();

private:

    // 在Poller中更新Channel
    void update();

    void handleEventWithGuard(Timestamp receiveTime);

    // channel感兴趣的事件的状态
    static const int kNoneEvent;   // 对任何事件不感兴趣
    static const int kReadEvent;   // 可读事件
    static const int kWriteEvent;  // 可写事件

    EventLoop *loop_; // 定义Channel所属的事件循环EventLoop
    int fd_;          // fd, poller监听的对象
    int events_;      // 注册fd感兴趣的事件
    int revents_;     // poller返回的具体发生的事件
    int index_;       // channel的初始状态
    std::weak_ptr<void> tie_;
    bool tied_;

    // 因为Channel通道能获知fd最终发生的具体事件revents，所以它负责调用具体事件的回调操作，根据事件的类型调用相应事件的回调
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
};